#ifndef __ELFX_H__
#define __ELFX_H__
#include<elf.h>

#include"./commonx.h"
/*
 * 本结构是对64位的elf文件的封装
 *
 */
typedef struct _elf64{
    mem_t bytes; //elf文件的字节缓存区
    struct stat *stat; //elf文件的stat结构,包含文件信息
    Elf64_Ehdr * ehdr;//elf文件头
    Elf64_Shdr * shdr_vec; //段表
    Elf64_Shdr * shstrtab_shdr; //shstrtab段描述符指针
    Elf64_Shdr * strtab_shdr; //strtab段描述符指针
    Elf64_Shdr * sym_shdr; //symtab段描述符指针
    Elf64_Shdr * dyn_sym_shdr; //.dynsym段描述符指针,动态库文件有这种段
    Elf64_Shdr * text_shdr; //.text段描述符指针
    Elf64_Shdr ** rel_shdr_vec;//重定位段表 
    int rel_shdr_vec_len; //重定位段表的数量
    mem_t text; //.text代码段
    mem_t data; //.data数据段
    mem_t rodata; //.rodata段
    Elf64_Sym * sym_vec; //symtab段指针
    Elf64_Sym * dyn_sym_vec; //.dynsym段指针
    mem_t shstrtab; //shstrtab段
    mem_t strtab; //strtab段
    Elf64_Phdr * phdr; //程序头

} elf64_t;

//获取在elf字节缓存区的指定偏移的字节值
#define value_in_elf_offset(elf,offset) ((elf)->bytes.ptr[(offset)]) 
// 获取elf位数: 1: 32位, 2: 64位
#define elf_bits(elf) value_in_elf_offset(elf,4) 

// 获取elf的大小端:  1 little endian
#define elf_endian(elf) value_in_elf_offset(elf,5) 

// 获取elf文件的大小,也是字节缓存区的长度
#define elf_size(elf) ((elf)->stat->st_size)

// 获取指定偏移在elf字节缓存区的地址
#define elf_bytes_offset_addr(elf,offset) ((elf)->bytes.ptr+(offset))

//通过偏移查找shstrtab字符表,段名在这个表中
#define get_shstr_in_offset(elf,offset) ((elf)->shstrtab.ptr+(offset))

//通过偏移查找strtab字符表,函数名，变量名在这个表中
#define get_str_in_offset(elf,offset) ((elf)->strtab.ptr+(offset))

//获取elf字节缓存区地址
#define elf_bytes_addr(elf) elf_bytes_offset_addr((elf),0) 

//获取段表中的段数量
#define elf_shdr_vec_num(elf) ((elf)->ehdr->e_shnum)

//解析64位的elf文件
elf64_t * parse_elf64_file(char * path);

/* 以下所有以PRT_开头的宏作为打印相关信息的位掩码*/
#define PRT_SHDR 1<<0 //段表掩码
#define PRT_SYM 1<<1 //符号表掩码
#define PRT_BUF 1<<2 //文件二进制掩码
#define PRT_EHDR 1<<3 //ELF文件头掩码
#define PRT_SHSTR 1<<4 //shstrtab表掩码
#define PRT_STR 1<<5 //strtab表掩码
#define PRT_STAT 1<<6 //文件stat掩码
#define PRT_TEXT 1<<7 //.text段掩码 
#define PRT_REL   1<<8 //重定位段掩码

//打印elf相关信息
void print_elf64(elf64_t * elf ,int mask);

char * e_type_map(int n);

char * e_machine_map(int n);

char * e_version_map(int n);

//获取段类型映射宏名
char * sh_type_map(elf64_t * elf, int n ); 

#endif
